package com.example.gyj.controller;

import com.example.gyj.access.AccessLimit;
import com.example.gyj.entity.OrderInfo;
import com.example.gyj.entity.SeckillOrder;
import com.example.gyj.entity.User;
import com.example.gyj.rabbitmq.MQSender;
import com.example.gyj.rabbitmq.SeckillMessage;
import com.example.gyj.redis.GoodsKey;
import com.example.gyj.redis.OrderKey;
import com.example.gyj.redis.SeckillKey;
import com.example.gyj.result.CodeMsg;
import com.example.gyj.result.Result;
import com.example.gyj.service.GoodsService;
import com.example.gyj.service.OrderService;
import com.example.gyj.service.RedisService;
import com.example.gyj.service.SeckillService;
import com.example.gyj.vo.GoodsVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;

/**
 * 秒杀
 * @author Gao
 * @date 2018/10/21
 */
@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private GoodsService goodsService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private SeckillService seckillService;
    @Autowired
    private MQSender sender;

    private HashMap<Long, Boolean> localOverMap = new HashMap<Long, Boolean>();

    /**
     * 实现InitializingBean的接口，系统初始化的时候调用的方法
     * 系统初始化，把秒杀商品库存加载到redis中
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> goodsVoList = goodsService.listGoodsVo();
        if (goodsVoList == null) {
            return;
        }
        for (GoodsVo goods : goodsVoList) {
            redisService.set(GoodsKey.getSeckillGoodsStrock, "" + goods.getId(), goods.getStockCount());
            localOverMap.put(goods.getId(), false);
        }
    }

    /**
     * 秒杀接口
     * @param model
     * @param user
     * @param goodsId
     * @param path
     */
    @RequestMapping(value = "/{path}/seckill1.do", method = RequestMethod.POST)
    @ResponseBody
    public String seckillList1(Model model, User user, @RequestParam("goodsId") long goodsId,
                               @PathVariable("path") String path) {
        //判断用户是否登录
        if (user == null) {
            return "login";
        }
        //判断库存
        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
        int stock = goods.getStockCount();
        if (stock <= 0) {
            model.addAttribute("errmsg", CodeMsg.MIAO_SHA_OVER.getMsg());
            return "seckill_fail";
        }
        //判断是否已经秒杀到了
        SeckillOrder order = orderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            model.addAttribute("errmsg", CodeMsg.REPEATE_SECKILL.getMsg());
            return "seckill_fail";
        }
        //减库存下订单 写入秒杀订单
        OrderInfo orderInfo = seckillService.seckill(user, goods);
        model.addAttribute("orderInfo", orderInfo);
        model.addAttribute("goods", goods);
        return "order_detail";
    }

    /**
     * 秒杀接口优化
     * @param user
     * @param goodsId
     * @param path
     */
    @RequestMapping(value = "/{path}/seckill.do", method = RequestMethod.POST)
    @ResponseBody
    public Result<Integer> seckillList(User user, @RequestParam("goodsId") long goodsId,
                                       @PathVariable("path") String path) {
        //判断用户是否登录
        if (user == null) {
            //Session不存在或者已经失效
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        //验证path
        boolean check = seckillService.checkPath(user, goodsId, path);
        if (!check) {
            return Result.error(CodeMsg.REQUEST_ILLEGAL);
        }
        //内存标记，减少redis访问
        Boolean over = localOverMap.get(goodsId);
        if (over) {
            //商品已经秒杀完毕
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }
        //预减库存
        Long stock = redisService.decr(GoodsKey.getSeckillGoodsStrock, "" + goodsId);
        if (stock < 0) {
            //当过来的请求数大于库存的数量时，设置标记位，减少redis访问
            localOverMap.put(goodsId, true);
            //商品已经秒杀完毕
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }
        //判断是否已经秒杀到了
        SeckillOrder order = orderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            //不能重复秒杀
            return Result.error(CodeMsg.REPEATE_SECKILL);
        }
        // 入队
        SeckillMessage message = new SeckillMessage();
        message.setUser(user);
        message.setGoodsId(goodsId);
        sender.sendSeckillMessage(message);
        // 排队中
        return Result.success(0);
    }

    /**
     * 获取秒杀结果
     * orderId: 成功
     * -1: 秒杀失败
     * 0: 排队中
     */
    @RequestMapping(value = "/result", method = RequestMethod.GET)
    @ResponseBody
    public Result<Long> SeckillResult(Model model, User user, @RequestParam("goodsId") long goodsId) {

        model.addAttribute("user", user);
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);  //Session不存在或者已经失效
        }
        //获取秒杀结果
        long result = seckillService.getSeckillResult(user.getId(), goodsId);
        return Result.success(result);
    }

    @RequestMapping(value = "/reset", method = RequestMethod.GET)
    @ResponseBody
    public Result<Boolean> reset(Model model) {
        List<GoodsVo> goodsVoList = goodsService.listGoodsVo();
        for (GoodsVo goods : goodsVoList) {
            goods.setStockCount(10);
            redisService.set(GoodsKey.getSeckillGoodsStrock, "" + goods.getId(), 10);
            localOverMap.put(goods.getId(), false);
        }

        redisService.delete(OrderKey.getSeckillOrderByUidGid);
        redisService.delete(SeckillKey.isGoodsOver);
        seckillService.reset(goodsVoList);

        return Result.success(true);
    }

    /**
     * 生成图形验证码
     *
     * @param response
     * @param user
     * @param goodsId
     */
    @RequestMapping(value = "/verifyCode", method = RequestMethod.GET)
    @ResponseBody
    public Result<String> getSeckillVerifyCode(HttpServletResponse response, User user, @RequestParam("goodsId") long goodsId) {
        if (user == null) {
            //Session不存在或者已经失效
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        try {
            BufferedImage image = seckillService.createVerifyCode(user, goodsId);
            OutputStream out = response.getOutputStream();
            ImageIO.write(image, "JPEG", out);
            out.flush();
            out.close();
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(CodeMsg.SECKILL_FAIL);
        }
    }

    /**
     * 秒杀路径
     * @param user
     * @param goodsId
     * @param verifyCode
     */
    @AccessLimit(seconds = 5, maxCount = 5, needLogin = true)
    @RequestMapping(value = "/path", method = RequestMethod.GET)
    @ResponseBody
    public Result<String> getSeckillPath(User user, @RequestParam("goodsId") long goodsId,
                                         @RequestParam(value = "verifyCode", defaultValue = "0") int verifyCode) {
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        boolean check = seckillService.checkVerifyCode(user, goodsId, verifyCode);
        if (!check) {
            return Result.error(CodeMsg.REQUEST_ILLEGAL);
        }
        //创建秒杀路径，隐藏秒杀接口地址
        String path = seckillService.createSeckillPath(user, goodsId);
        return Result.success(path);
    }
}
